package org.redr.widgetGUI.core;

import java.util.HashMap;

import org.redr.canvas.OSPath;
import org.redr.canvas.RRW;
import org.redr.canvas.RSession;
import org.redr.canvas.RedRApplication;
import org.redr.canvas.RedRLog;
import org.redr.canvas.RedRObjects;
import org.redr.widgetGUI.settings.WidgetSettings;
import org.redr.widgetGUI.settings.WidgetState;
import org.rosuda.REngine.REXP;

import com.trolltech.qt.core.QCoreApplication;
import com.trolltech.qt.core.QEvent;
import com.trolltech.qt.core.Qt;
import com.trolltech.qt.core.Qt.DockWidgetArea;
import com.trolltech.qt.gui.QDockWidget;
import com.trolltech.qt.gui.QDockWidget.DockWidgetFeature;
import com.trolltech.qt.gui.QHBoxLayout;
import com.trolltech.qt.gui.QIcon;
import com.trolltech.qt.gui.QLabel;
import com.trolltech.qt.gui.QMainWindow;
import com.trolltech.qt.gui.QPalette.ColorRole;
import com.trolltech.qt.gui.QPixmap;
import com.trolltech.qt.gui.QPushButton;
import com.trolltech.qt.gui.QSizePolicy;
import com.trolltech.qt.gui.QSizePolicy.Policy;
import com.trolltech.qt.gui.QStatusBar;
import com.trolltech.qt.gui.QVBoxLayout;
import com.trolltech.qt.gui.QWidget;

public class RedRWidgetGUI extends LayoutState{
	protected 	String 		icon = OSPath.join(RedRApplication.parentDir,  "coreIcons", "default.png").getAbsolutePath();	
	protected 	boolean		locked	=	false;
	public 	static 	int 	widgetNumber	=	0;
	public 	static 	String	globalRHistory = "";
	private String 			widgetID;
	public 	QMainWindow 	mainWindow;
	public 	WidgetBox		controlArea;
	public 	WidgetBox			topWidgetPart;
	public 	WidgetBox		bottomWidgetPart;
	public 	WidgetBox		bottomAreaLeft;
	public	WidgetBox		bottomAreaCenter;
	public	WidgetBox		bottomAreaRight;
	public	QStatusBar		statusBar;
	public 	QLabel			rIndicator;
	public 	StatusLabel		statusLabel;
	public	QDockWidget		notesDock;
	public 	QWidget			notesBox;
	public 	TextEdit			notes;
	public 	QDockWidget		rVarNamesDock;
	public 	QWidget			rVarNamesBox;
	protected 	QDockWidget		rOutputDock;
	protected 	QWidget			rOutputBox;
	protected 	TextEdit			rOutput;
	protected 	QDockWidget		leftDock;
	protected 	QWidget			guiDialog;
	protected 	QPushButton		leftDockButton;
	protected 	QPixmap			redIndicator;
	protected 	QPixmap			greenIndicator;
	protected 	QPushButton		showHelp;
	protected 	QPushButton		showROutput;
	protected 	QPushButton		showNotesButton;
	protected QPushButton		showRVarNamesButton;
	protected QPushButton		showPrintButton;
	
	private HashMap<String, String>		rVariables	=			new HashMap<String, String>();
	private HashMap<String, LineEdit> 	rVariableNameEdits	=	new HashMap<String, LineEdit>();
	
	public String widgetID(){
		return widgetID;
	}
	
	protected static int newWidgetNumber(){
		return widgetNumber++;
	}
	
	@Override
	public void addWidget(WidgetState w){
		controlArea.addWidget(w.getWidgetBox());
	}
	
	@Override
	public void addWidget(QWidget w){
		controlArea.addWidget(w);
	}
	
	
	public RedRWidgetGUI(WidgetSettings ws){
		
		super(ws);
		widgetID	=	_getSetting("wid", String.valueOf(newWidgetNumber()));
		mainWindow	=	new QMainWindow();
//		mainWindow.setLayout(new QVBoxLayout());
//		mainWindow.layout().setMargin(2);
		mainWindow.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding);
		// set the widget layouts
		//topWidgetPart
		
		// mainWindow.setBackgroundRole(ColorRole.Dark);
		mainWindow.setCentralWidget(widgetBox);
		// widgetBox.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding);
		widgetBox.layout().setMargin(4);
		topWidgetPart	=	new WidgetBox(widgetBox.layout(), (WidgetSettings) ws.getSettings("topWidgetPart")
				.setDefault("label", "_topWidgetPart"));
		// topWidgetPart.setLayout(new QVBoxLayout());
		// topWidgetPart.layout().setMargin(4);
		// topWidgetPart.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding);
		// mainWindow.setCentralWidget(topWidgetPart);
		
		//controlArea
		controlArea = new WidgetBox(topWidgetPart, (WidgetSettings) ws.getSettings("controlArea")
				.setSetting("layout", "vertical")
			);
		// controlArea.widget().setMinimumWidth(200);
		controlArea.widget().setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum);
	
		controlArea.widget().layout().setMargin(4);
		
		// topWidgetPart.layout().setAlignment(controlArea.widget(), Qt.AlignmentFlag.AlignTop, Qt.AlignmentFlag.AlignLeft);
		
		//bottomArea
		bottomWidgetPart	=	new WidgetBox(topWidgetPart, (WidgetSettings) ws.getSettings("bottomWidgetPart")
				.setSetting("layout", "horizontal"));
		bottomWidgetPart.widget().setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed);
		
		bottomAreaLeft		=	new WidgetBox(bottomWidgetPart, (WidgetSettings) ws.getSettings("bottomAreaLeft")
				.setSetting("layout", "horizontal"));
		
		bottomAreaCenter	=	new WidgetBox(bottomWidgetPart, (WidgetSettings) ws.getSettings("bottomAreaLeft")
				.setSetting("layout", "horizontal"));
		bottomAreaCenter.widget().setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed);
		
		bottomAreaRight		=	new WidgetBox(bottomWidgetPart, (WidgetSettings) ws.getSettings("bottomAreaLeft")
				.setSetting("layout", "horizontal"));
	
		//statusBar
		statusBar	=	new QStatusBar();
		statusBar.setSizeGripEnabled(false);
		mainWindow.setStatusBar(statusBar);
		rIndicator	=	new QLabel();
		statusBar.addWidget(rIndicator);
		WidgetSettings statusSettings	=	settings.getSettings("_reserved_Status");
		statusSettings.setDefault("status", "0");
		statusLabel	=	new StatusLabel(statusBar.layout(), statusSettings);
		statusLabel.widget().setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum);
		statusBar.addPermanentWidget(statusLabel.widget(), 4);
		greenIndicator	=	new QPixmap(OSPath.join(RedRApplication.parentDir, "coreIcons", "greenLight.png").getAbsolutePath());
		redIndicator	=	new QPixmap(OSPath.join(RedRApplication.parentDir, "coreIcons", "redLight.png").getAbsolutePath());
		_setRIndicator(false);
		
		//dock widgets
		int minWidth	=	200;
		notesDock	=	new QDockWidget("Notes");
		notesDock.setObjectName("widgetNotes");
		notesDock.topLevelChanged.connect(this, "updateDock(boolean)");
		notesDock.setFeatures(DockWidgetFeature.DockWidgetMovable, DockWidgetFeature.DockWidgetFloatable);
		notesDock.setMinimumWidth(minWidth);
		notesDock.setAllowedAreas(DockWidgetArea.TopDockWidgetArea, DockWidgetArea.RightDockWidgetArea, DockWidgetArea.BottomDockWidgetArea);
		mainWindow.addDockWidget(DockWidgetArea.RightDockWidgetArea, notesDock);
		notesBox	=	new QWidget();
		notesBox.setLayout(new QVBoxLayout());
		notesBox.layout().addWidget(new QLabel("Notes"));
		WidgetSettings notesSettings	=	settings.getSettings("_reserved_Notes");
		notesSettings.setDefault("text", "");
		notes	=	new TextEdit(notesBox.layout(), notesSettings);
		notesBox.setMinimumHeight(50);
		notesBox.setSizePolicy(Policy.Expanding, Policy.Expanding);
		
		notesDock.setWidget(notesBox);
		
		rVarNamesDock	=	new QDockWidget("R Variable Names");
		rVarNamesDock.setObjectName("RVarNamesDock");
		rVarNamesDock.topLevelChanged.connect(this, "updateDock(boolean)");
		rVarNamesDock.setFeatures(DockWidgetFeature.DockWidgetMovable, DockWidgetFeature.DockWidgetFloatable);
		rVarNamesDock.setMinimumWidth(minWidth);
		rVarNamesDock.setAllowedAreas(DockWidgetArea.TopDockWidgetArea, DockWidgetArea.RightDockWidgetArea, DockWidgetArea.BottomDockWidgetArea);
		mainWindow.addDockWidget(DockWidgetArea.RightDockWidgetArea, rVarNamesDock);
		rVarNamesBox	=	new QWidget();
		rVarNamesBox.setLayout(new QVBoxLayout());
		rVarNamesDock.setWidget(rVarNamesBox);
		rVarNamesBox.setMinimumHeight(50);
		rVarNamesBox.layout().addWidget(new QLabel("R Variable Names"));
		QPushButton	varNamesButton	=	new QPushButton();
		varNamesButton.setText("Accept Names");
		varNamesButton.setToolTip("This resets the R variable names for this widget to the indicated names.  This should only be done if the user really knows what she is doing!!");
		varNamesButton.clicked.connect(this, "_protected_namesChanged(boolean)");
		rVarNamesBox.layout().addWidget(varNamesButton);
		
		rOutputDock	=	new QDockWidget("R Output");
		rOutputDock.setObjectName("ROutputDock");
		rOutputDock.topLevelChanged.connect(this, "updateDock(boolean)");
		rOutputDock.setFeatures(DockWidgetFeature.DockWidgetMovable, DockWidgetFeature.DockWidgetFloatable);
		rOutputDock.setMinimumWidth(minWidth);
		rOutputDock.setAllowedAreas(DockWidgetArea.TopDockWidgetArea, DockWidgetArea.RightDockWidgetArea, DockWidgetArea.BottomDockWidgetArea);
		mainWindow.addDockWidget(DockWidgetArea.RightDockWidgetArea, rOutputDock);
		rOutputBox	=	new QWidget();
		rOutputBox.setLayout(new QVBoxLayout());
		rOutputDock.setWidget(rOutputBox);
		rOutputBox.setMinimumHeight(50);
		rOutputBox.layout().addWidget(new QLabel("R Code Executed In This Widget:"));
		WidgetSettings	rOutputSettings	=	settings.getSettings("_protected_ROutput");
		rOutputSettings.setDefault("text", "");
		rOutput	=	new TextEdit(rOutputBox.layout(), rOutputSettings);
		
		//doc control box
		QWidget docBox	=	new QWidget();
		docBox.setLayout(new QHBoxLayout());
		
		showNotesButton = new QPushButton();
		docBox.layout().addWidget(showNotesButton);
		showNotesButton.setCheckable(true);
		showNotesButton.setIcon(new QIcon(OSPath.join(RedRApplication.parentDir, "coreIcons", "Notes-icon.png").getAbsolutePath()));
		showNotesButton.setToolTip("Toggle show notes");
		showNotesButton.clicked.connect(this, "updateDocumentationDock(boolean)");

		showRVarNamesButton	=	new QPushButton();
		docBox.layout().addWidget(showRVarNamesButton);
		showRVarNamesButton.setCheckable(true);
		showRVarNamesButton.setIcon(new QIcon(OSPath.join(RedRApplication.parentDir, "coreIcons", "options.png").getAbsolutePath()));
		showRVarNamesButton.setToolTip("Toggle show RVarNames");
		showRVarNamesButton.clicked.connect(this, "updateDocumentationDock(boolean)");
		
		showROutput	=	new QPushButton();
		docBox.layout().addWidget(showROutput);
		showROutput.setCheckable(true);
		showROutput.setIcon(new QIcon(OSPath.join(RedRApplication.parentDir, "coreIcons", "R_icon.png").getAbsolutePath()));
		showROutput.setToolTip("Toggle show R Code");
		showROutput.clicked.connect(this, "updateDocumentationDock(boolean)");
		
		showPrintButton	=	new QPushButton();
		docBox.layout().addWidget(showPrintButton);
		showPrintButton.setCheckable(true);
		showPrintButton.setIcon(new QIcon(OSPath.join(RedRApplication.parentDir, "coreIcons", "printer_icon.png").getAbsolutePath()));
		showPrintButton.setToolTip("Include In Reports");
		showPrintButton.clicked.connect(this, "updateDocumentationDock(boolean)");
		
		showHelp	=	new QPushButton();
		docBox.layout().addWidget(showHelp);
		showHelp.setIcon(new QIcon(OSPath.join(RedRApplication.parentDir, "coreIcons", "help_icon.png").getAbsolutePath()));
		showHelp.setToolTip("Show Help");
		showHelp.clicked.connect(this, "_protected_showHelp(boolean)");
		statusBar.addPermanentWidget(docBox);
		ws.setDefault("advancedOptions", "false");
		if (ws.getSetting("advancedOptions").equals("true")){
			leftDock	=	new QDockWidget("Advanced Options");
			leftDock.setObjectName("leftDock");
			leftDock.topLevelChanged.connect(this, "updateDock(boolean)");
			leftDock.setFeatures(DockWidgetFeature.DockWidgetMovable, DockWidgetFeature.DockWidgetFloatable);
			leftDock.setSizePolicy(Policy.Minimum, Policy.Minimum);
			mainWindow.addDockWidget(DockWidgetArea.LeftDockWidgetArea, leftDock);
			leftDock.setLayout(new QVBoxLayout());
			guiDialog	=	new QWidget();
			guiDialog.setLayout(new QVBoxLayout());
			leftDock.setWidget(guiDialog);
			guiDialog.setSizePolicy(Policy.Minimum, Policy.Minimum);
			leftDockButton	=	new QPushButton();
			leftDockButton.setText("Advanced Options");
			leftDockButton.setCheckable(true);
			leftDockButton.clicked.connect(this, "showLeftDock(boolean)");
			statusBar.insertPermanentWidget(2, leftDockButton);
		}else{
			leftDock = null;
			leftDockButton = null;
			guiDialog = null;
		}
		
		mainWindow.setWindowTitle(ws.getSetting("caption"));
		mainWindow.setWindowIcon(new QIcon(icon));
	}
	
	protected void _protected_namesChanged(boolean b){
		
	}
	
	protected void _protected_showHelp(boolean b){
		
	}
	
	@SuppressWarnings("unused")
	private void _acceptNameChanges(){
		for (String k : rVariables.keySet()){
			try{
				if (rVariableNameEdits.get(k).text().equals("")) continue;
				String newName = rVariableNameEdits.get(k).text();
				R(String.format("if(exists(%s)){%s<-%s; rm(%s)}", rVariables.get(k), rVariables.get(k), rVariables.get(k), rVariables.get(k)));
				rVariables.put(k, newName);
			} catch (Exception e){
				e.printStackTrace();
			}
		}
		_resetRVariableNameEdits();
	}
	
	private void _resetRVariableNameEdits(){
		_clearRVariableNameEdits();
		for (String k : rVariables.keySet()){
			WidgetSettings	les	= settings.getSettings(String.format("_protected_rVariabelEdit_%s", k));
			les.setDefault("label", k);
			les.setDefault("text", rVariables.get(k));
			rVariableNameEdits.put(k, new LineEdit(rVarNamesBox.layout(), les));
		}
	}
	
	private void _clearRVariableNameEdits(){
		for (LineEdit v : rVariableNameEdits.values()){
			v.hide();
			v.delete();
		}
		rVariableNameEdits.clear();
	}
	
	private void _setRIndicator(boolean active){
		if (active){
			rIndicator.setPixmap(redIndicator);
			rIndicator.setToolTip("Red-R is currently running. Please wait...");
		}else{
			rIndicator.setPixmap(greenIndicator);
			rIndicator.setToolTip("Red-R is idle.");
			
		}
		QCoreApplication.processEvents();
	}
	
	private REXP R(String command){
		return R(command, false);
	}
	
	private REXP R(String command, boolean silent){
		REXP result = new REXP();
		_setRIndicator(true);
		// set wait cursor
		try{
			result	=	RSession.R(command);
		} catch(Exception e){
			statusLabel.setStatus(StatusLabel.ERROR);
			e.printStackTrace();
		}
		if (!silent){
			globalRHistory += "\n"+command;
			rOutput.append("> "+command);
		}
		_setRIndicator(false);
		return result;
	}
	
	
	public void updateDock(boolean d){
		if (notesDock.isFloating()){
			notesDock.setWindowTitle(mainWindow.windowTitle() + " Notes");
			
		} else {
			notesDock.setWindowTitle("Notes");
		}
		
		if (rOutputDock.isFloating()){
			rOutputDock.setWindowTitle(mainWindow.windowTitle() + " R Output");
			
		} else {
			rOutputDock.setWindowTitle("R Output");
		}
		
		if (leftDock != null){
			if (leftDock.isFloating()){
				leftDock.setWindowTitle(mainWindow.windowTitle() + " Advanced Options");
				
			} else {
				leftDock.setWindowTitle("Advanced Options");
			}
		}
	}
	
	public void showLeftDock(){
		if (leftDock == null) return;
		if (leftDockButton.isChecked()){
			leftDock.show();
			_setSetting("leftDockStateShown", "true");
		} else {
			leftDock.hide();
			_setSetting("leftDockStateShown", "false");
		}
	}
	
	public void updateDocumentationDock(boolean d){
		if (showNotesButton.isChecked()){
			notesDock.show();
			_setSetting("notesDockShown", "true");
		} else {
			notesDock.hide();
			_setSetting("notesDockShown", "false");
		}
		
		if (showROutput.isChecked()){
			rOutputDock.show();
			_setSetting("rOutputDockShown", "true");
		} else {
			rOutputDock.hide();
			_setSetting("rOutputDockShown", "false");
		}
		
		if (showRVarNamesButton.isChecked()){
			rVarNamesDock.show();
			_setSetting("rVarNamesDockShown", "true");
		} else {
			rVarNamesDock.hide();
			_setSetting("rVarNamesDockShown", "false");
		}
	}
	
	protected void _saveWidgetWindowState(){
		_setSetting("xposition", String.valueOf(mainWindow.pos().x()));
		_setSetting("yposition", String.valueOf(mainWindow.pos().y()));
		_setSetting("width", String.valueOf(mainWindow.size().width()));
		_setSetting("height", String.valueOf(mainWindow.size().height()));
	}
	
	public void closeEvent(QEvent ev){
		if (notesDock.isFloating()){
			notesDock.hide();
		}
		if (rOutputDock.isFloating()){
			rOutputDock.hide();
		}
		if (leftDock != null){
			if (leftDock.isFloating()){
				leftDock.hide();
			}
		}
		
		//for (QObject i : mainWindow.findChildren(QDialog)){
			
		//saveGlobalSettings();
		customCloseEvent();
	}
	
	public void customCloseEvent(){
		return;
	}
	
	@Override
	public void show(){
		mainWindow.resize(Integer.parseInt(_getSetting("width", "-1")), Integer.parseInt(_getSetting("height", "-1")));
		mainWindow.move(Integer.parseInt(_getSetting("xposition", "0")), Integer.parseInt(_getSetting("yposition", "0")));
		if (leftDock != null){
			leftDockButton.setChecked(Boolean.parseBoolean(_getSetting("leftDockStateShown", "true")));
		}
		showNotesButton.setChecked(Boolean.parseBoolean(_getSetting("notesDockShown", "true")));
		showRVarNamesButton.setChecked(Boolean.parseBoolean(_getSetting("rVarNamesDockShown", "false")));
		showROutput.setChecked(Boolean.parseBoolean(_getSetting("rOutputDockShown", "false")));
		updateDocumentationDock(true);
		mainWindow.show();
		QCoreApplication.processEvents();
	}
	
	public void setWidgetWindowIcon(String iconName){
		QIcon icon	=	new QIcon(iconName);
		mainWindow.setWindowIcon(icon);
	}
	
	public static void log(String message){
		log(message, RedRLog.devel);
	}
	
	public static void log(String message, int level){
		RedRLog.log(RedRLog.widget, level, message);
	}
	
	public void setRVariableNames(String...names){
		for (String n : names){
			rVariables.put(n, n+"_"+widgetID);
		}
		_resetRVariableNameEdits();
	}
	
	public String getReportText(){
		return "No report text entered for this widget";
	}
	
	public void require_libraries(String...libraries){
		for (String s : libraries){
			require_libraries(s);
		}
	}
	
	public void require_library(String library){
		try {
			RSession.require_library(library);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void onDeleteWidget(){
		if (!locked){
			for (String k : rVariables.keySet()){
				try{
					R(String.format("if(exist\"%s\"){rm(%s)}", k, k));
				} catch (Exception e){
					e.printStackTrace();
				}
			}
		}
		// GlobalData.removeGlobalData(this);
		customWidgetDelete();
	}
	
	public void customWidgetDelete(){
		// dummy function, implement in child classes if needed
	}
	
	public void refresh(){
		// dummy function, implement in child classes if needed
	}
	
	public void sendRefresh(){
		for (RRW w : RedRObjects.widgets()){
			// TODO w.refresh();
		}
	}

	public void setWindowTitle(String newName) {
		// TODO Auto-generated method stub
		settings.setSetting("caption", newName);
		mainWindow.setWindowTitle(newName);
		
	}

	@Override
	public void removeWidget(WidgetState ws) {
		// TODO Auto-generated method stub
		controlArea.removeWidget(ws);
	}

	@Override
	public void removeWidget(QWidget w) {
		// TODO Auto-generated method stub
		controlArea.removeWidget(w);
	}

}
